package Process

import (
	"fmt"
	"log"
	"log_process/service/Reader"
	"log_process/service/Writer"
	"log_process/system"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type LogProcess struct {
	ReadChan  chan []byte
	WriteChan chan *system.Message
	Reader    Reader.Reader
	Writer    Writer.Writer
}

func InitLogProcess(reader Reader.Reader, writer Writer.Writer) *LogProcess {
	return &LogProcess{
		Reader:    reader,
		Writer:    writer,
		ReadChan:  make(chan []byte, 1000),
		WriteChan: make(chan *system.Message, 1000),
	}
}

func (lg *LogProcess) Process() {

	var (
		data     []byte
		reg      *regexp.Regexp
		regData  []string
		location *time.Location
		err      error
		t        time.Time
		message  *system.Message
	)

	reg = regexp.MustCompile(`([\d\.]+)\s+([^ \[]+)\s+([^ \[]+)\s+\[([^\]]+)\]\s+([a-z]+)\s+\"([^"]+)\"\s+(\d{3})\s+(\d+)\s+\"([^"]+)\"\s+\"(.*?)\"\s+\"([\d\.-]+)\"\s+([\d\.-]+)\s+([\d\.-]+)`)

	if location, err = time.LoadLocation("Asia/Shanghai"); err != nil {
		system.TypeMonitorChan <- system.TypeErrNum
		panic(fmt.Sprintf("LoadLocation error：%s", err.Error()))
	}

	for data = range lg.ReadChan {

		regData = reg.FindStringSubmatch(string(data))

		if len(regData) != 14 {
			system.TypeMonitorChan <- system.TypeErrNum
			log.Println(fmt.Sprintf("FindStringSubmatch error：%s", string(data)))
			continue
		}

		if t, err = time.ParseInLocation("02/Jan/2006:15:04:05 +0800", regData[4], location); err != nil {
			system.TypeMonitorChan <- system.TypeErrNum
			log.Println(fmt.Sprintf("ParseInLocation error：%s，%s", err.Error(), regData[4]))
			continue
		}

		message = &system.Message{}
		message.TimeLocal = t

		byteSent, _ := strconv.Atoi(regData[8])
		message.BytesSent = byteSent

		reqSli := strings.Split(regData[6], " ")
		if len(reqSli) != 3 {
			system.TypeMonitorChan <- system.TypeErrNum
			log.Println(fmt.Sprintf("Split error：%s", regData[6]))
			continue
		}
		message.Method = reqSli[0]

		u, err := url.Parse(reqSli[1])
		if err != nil {
			log.Println(fmt.Sprintf("Parse error：%s", err.Error()))
			system.TypeMonitorChan <- system.TypeErrNum
			continue
		}
		message.Path = u.Path

		message.Scheme = regData[5]
		message.Status = regData[7]

		upstreamTime, _ := strconv.ParseFloat(regData[12], 64)
		requestTime, _ := strconv.ParseFloat(regData[13], 64)

		message.UpstreamTime = upstreamTime
		message.RequestTime = requestTime

		lg.WriteChan <- message
	}
}
